package com.jasperframework.boot.common.utils;

import javax.crypto.Cipher;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

/**
  * <p>  </p>
  *
  * @site https://miliqkdoc.motopa.cn/
  * @author daizhao
  * @date 2022/12/12 12:12
  */
public class RSABase64Utils {

    private static final String ALGORITHM = "RSA";

    private static final Integer KEY_SIZE = 512*8;

    /**
     *  @Author daizhao
     *  @Date 2018-4-3 11:18
     *  @Params []
     *  @Return void
     *  @Info  生成密钥对
     */
    public static Map<String, String> generateKeyPair() throws Exception{
        /** RSA算法要求有一个可信任的随机数源 */
        SecureRandom sr = new SecureRandom();
        /** 为RSA算法创建一个KeyPairGenerator对象 */
        KeyPairGenerator kpg = KeyPairGenerator.getInstance(ALGORITHM);
        /** 利用上面的随机数据源初始化这个KeyPairGenerator对象 */
        kpg.initialize(KEY_SIZE, sr);
        /** 生成密匙对 */
        KeyPair kp = kpg.generateKeyPair();
        /** 得到公钥 */
        Key publicKey = kp.getPublic();
        /** 得到私钥 */
        Key privateKey = kp.getPrivate();
        /** 用base64编码处理密钥 */
        String publicKeyStr = BASE64Utils.getEncodeBase64(publicKey.getEncoded());
        String privateKeyStr = BASE64Utils.getEncodeBase64(privateKey.getEncoded());
        Map<String, String> pairMap = new HashMap<String, String>();
        pairMap.put("publicKey", publicKeyStr);
        pairMap.put("privateKey", privateKeyStr);
        return pairMap;
    }

    /**
     *  @Author daizhao
     *  @Date 2018-4-8 11:42
     *  @Params [source：要进行加密的内容, privateKey：加密的私钥]
     *  @Return java.lang.String
     *  @Info  RSA加密算法
     */
    public static String encrypt(String source, String privateKey) throws Exception{
        /** privateKey base64——>key(将base64转码为Key) */
        Key key = getPrivateKey(privateKey);
        /** 得到Cipher对象来实现对源数据的RSA加密 */
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, key);
        byte[] b = source.getBytes();
        /** 执行加密操作 */
        byte[] b1 = cipher.doFinal(b);
        return BASE64Utils.getEncodeBase64(b1);
    }

    /**
     *  @Author daizhao
     *  @Date 2018-4-8 11:45
     *  @Params [cryptograph：密文, publicKey：公钥]
     *  @Return java.lang.String
     *  @Info  RSA解密算法
     */
    public static String decrypt(String cryptograph, String publicKey) throws Exception{
        /** publicKey base64——>key(将base64转码为Key) */
        Key key = getPublicKey(publicKey);
        /** 得到Cipher对象对已用私钥加密的数据进行RSA解密 */
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, key);
        byte[] b1 = BASE64Utils.decodeBase64(cryptograph);
        /** 执行解密操作 */
        byte[] b = cipher.doFinal(b1);
        return new String(b);
    }

    /**
     *  @Author daizhao
     *  @Date 2018-4-8 13:40
     *  @Params [base64Key：base64编码字符串]
     *  @Return java.security.PublicKey
     *  @Info 根据PublicKey的base64编码的字符串 获取公钥
     */
    private static PublicKey getPublicKey(String base64Key) throws Exception {
        byte[] keyBytes = BASE64Utils.decodeBase64(base64Key);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey publicKey = keyFactory.generatePublic(keySpec);
        return publicKey;
    }

    /**
     *  @Author daizhao
     *  @Date 2018-4-8 13:40
     *  @Params [base64Key：base64编码字符串]
     *  @Return java.security.PrivateKey
     *  @Info  根据PrivateKey的base64编码的字符串 获取私钥
     */
    private static PrivateKey getPrivateKey(String base64Key) throws Exception {
        byte[] keyBytes = BASE64Utils.decodeBase64(base64Key);
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
        return privateKey;
    }

    public static void main(String[] args) {
        try {
            Map<String, String> pairMap = generateKeyPair();
            String publicKey = pairMap.get("publicKey");
            String privateKey = pairMap.get("privateKey");
            String encryptStr = encrypt(DesUtil.CRYPT_KEY, privateKey);
            String decryptStr = decrypt(encryptStr, publicKey);
            System.out.println("encryptStr：" + encryptStr + "，privateKey：" + privateKey);
            System.out.println("decryptStr：" + decryptStr + "，publicKey：" + publicKey);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

